package edu.hda.pt.utils.connections.mina.codec;

import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;

import edu.hda.pt.client.Config;
import edu.hda.pt.utils.Stream;
import edu.hda.pt.utils.TestObject;
import edu.hda.pt.utils.Stream.StreamState;
import edu.hda.pt.utils.connections.mina.MinaConstants;

/**
 * This class encodes a message before it is sent to either the client or the
 * server
 * 
 * @author Marc Hammerton
 * 
 */
public class MessageEncoder implements ProtocolEncoder {

	/**
	 * @see org.apache.mina.filter.codec.ProtocolEncoder#dispose(org.apache.mina.
	 *      core.session.IoSession)
	 */
	@Override
	public void dispose(IoSession arg0) throws Exception {
	}

	/**
	 * This method encodes the message by adding a header to the value and
	 * putting the whole message into a buffer.
	 * 
	 * @see org.apache.mina.filter.codec.ProtocolEncoder#encode(org.apache.mina.core
	 *      .session.IoSession, java.lang.Object,
	 *      org.apache.mina.filter.codec.ProtocolEncoderOutput)
	 */
	@Override
	public void encode(IoSession session, Object message,
			ProtocolEncoderOutput out) throws Exception {
		IoBuffer buf = IoBuffer.allocate(3);
		buf.setAutoExpand(true);

		if (message instanceof Boolean) {
			buf.putShort(Config.HANDLEBOOL);
			buf.put(((Boolean) message) == true ? (byte) 1 : (byte) 0);
		} else if (message instanceof byte[]) {
			byte[] data = (byte[]) message;
			buf.putShort(Config.HANDLEBYTES);
			buf.putInt(data.length);
			buf.put(data);
		} else if (message instanceof Integer) {
			buf.putShort((short) Config.HANDLEINTEGER);
			buf.putInt((Integer) message);
		} else if (message instanceof Long) {
			buf.putShort((short) Config.HANDLELONG);
			buf.putLong((Long) message);
		} else if (message instanceof TestObject) {
			buf.putShort((short) Config.HANDLEOBJECT);
			buf.putInt(0);
			buf.putObject((TestObject) message);
			buf.putInt(MinaConstants.HEADER_LENGTH_SHORT,
					(buf.position() - MinaConstants.HEADER_LENGTH_LONG));

		} else if (message instanceof String) {
			String value = (String) message;

			buf.putShort(Config.HANDLESTRING);
			buf.putInt(value.getBytes().length);
			try {
				buf.putString(value, Charset.forName("UTF-8").newEncoder());
			} catch (CharacterCodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} else if (message instanceof Stream) {
			Stream stream = (Stream) message;
			if (stream.getState() == StreamState.START) {
				buf.putShort(Config.HANDLESTREAM_START);
				buf.putInt(stream.getFs());
			} else if (stream.getState() == StreamState.RUNNING) {
				buf.putShort(Config.HANDLESTREAM_STARTED);
			} else if (stream.getState() == StreamState.FINISH) {
				buf.putShort(Config.HANDLESTREAM_STOP);
			}
		}

		buf.flip();
		out.write(buf);
		out.flush();

	}

}
